<template>
  <div class="role-container">
    <div class="rc-1">
      <el-button type="primary" size="medium" @click="showDialog = true">添加角色</el-button>
    </div>
    <div class="rc-2">
      <el-table
        :data="roleList"
        style="width: 100%"
      >
        <!-- 数组里面有多少列，取决于什么？ -->
        <!-- 取决于 table里面有多少个col开头的那个元素，有多个个table-col那个元素，就有多少列 -->
        <!-- 表格有多少行，取决于什么？ -->
        <!-- 取决于绑定到 el-table上面的 那个数组的长度。 这个数组有多少个元素，这个表格就会渲染多少行 -->
        <el-table-column
          prop="name"
          label="角色"
          width="180"
        >
          <template v-slot="{ row }">
            <div v-if="row.isEdit">
              <el-input v-model="editForm.name" />
            </div>
            <div v-else>{{ row.name }}</div>
          </template>
        </el-table-column>
        <el-table-column
          prop="state"
          label="启用"
          width="180"
        >
          <!-- 如果仅仅通过 prop来展示值，那么只能展示后端接口返回的数据，要想自定义结构，就需要使用 作用域插槽 -->
          <!-- <template slot-scope="slotScope"> -->
          <!-- 在table的列里面，插槽的值 就是一个对象，里面有个row属性，表当当前这一行的数据 -->
          <template slot-scope="{ row }">
            <!-- 作用域插槽的值是多少，我们要么看官网，要么自己写函数打印出来 -->
            <div v-if="row.isEdit">
              <el-switch
                v-model="editForm.state"
                active-color="#13ce66"
                :active-value="1"
                :inactive-value="0"
              />
            </div>
            <div v-else @click="test(row)">{{ row.state == 1 ? '已启用' : '未启用' }}， {{ row.isEdit }}</div>
          </template>
        </el-table-column>
        <el-table-column
          prop="description"
          label="描述"
        >
          <!-- vue3的插槽v-slot 新语法，只能放在标签 template上面 -->
          <!-- <template v-slot="{ row }"> -->
          <div slot-scope="{row}">
            <div v-if="row.isEdit">
              <el-input v-model="editForm.description" />
            </div>
            <div v-else>{{ row.description }}</div>
          </div>
        </el-table-column>
        <el-table-column
          fixed="right"
          label="操作"
          width="150"
        >
          <template slot-scope="{row}">
            <template v-if="row.isEdit">
              <el-button type="primary" size="small" @click="editSubmitTmp">确定</el-button>
              <el-button size="small" @click="row.isEdit = false">取消</el-button>
            </template>
            <template v-else>
              <el-button type="text" size="small">分配权限</el-button>
              <el-button type="text" size="small" @click="editRowTmp(row)">编辑</el-button>
              <el-popconfirm
                title="这是一段内容确定删除吗？"
                @onConfirm="confirm(row.id)"
              >
                <el-button slot="reference" type="text" size="small">删除</el-button>
              </el-popconfirm>
              <!-- <el-button type="text" size="small" @click="delRoleTmp(row.id)">删除</el-button> -->
            </template>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div class="rc-3">
      <!-- 只要是分页，必须有两个参数 当前页码值，每页显示条数 -->
      <!-- 分页插件基本是所有显示大量数据，必须有的一个优化，因为不分页的话，一个页面显示1000条数据，就会卡死
        如果有了分页，每页显示10条，浏览器渲染10个DOM元素，性能就会好一些
        element-ui的分页插件是 基本的模板结构，工作里面，只需要把下面代码复制过去，或者从element-ui官网复制过去
        就可以直接使用，这种代码叫基本结构代码，不是业务代码。 需要非常熟悉，一般有表格的地方就有分页，
       -->
      <!-- 学习基础很差的同学，把下面的每个属性什么含义？ 怎么使用？自己做笔记标注一下，多看自然就会了 -->
      <el-pagination
        layout="total, prev, pager, next"
        :total="total"
        :current-page="form.page"
        :page-size="form.pagesize"
        @current-change="handleCurrentChange"
      />
    </div>

    <!-- <div>
      <p v-if="123 > 1">123</p>
      <p v-if="123 > 1">456</p>
      <template v-if="123 > 1">
        <p>123</p>
        <p>456</p>
      </template>
      <p v-else>789</p>
    </div> -->

    <!-- 我们的弹窗 从那几个地方去写基本的骨架： 自己或同事已经写过的页面，element-ui官网， 百度 -->
    <el-dialog title="新增角色" :visible.sync="showDialog" :append-to-body="true" @close="close">
      <el-form ref="ruleForm" :model="addForm" :rules="rules">
        <el-form-item label="角色名称" label-width="150px" prop="name">
          <el-input v-model="addForm.name" />
        </el-form-item>
        <el-form-item label="启用" label-width="150px">
          <!-- :active-value="1"   是给组件传递 数字1 -->
          <!-- :active-value="'1'"  是给组件传递 字符串1 -->
          <!-- :active-value="num"  是给组件传递 js里面的变量 num -->
          <!-- active-value="1"    是给组件传递 字符串 1 -->
          <el-switch
            v-model="addForm.state"
            active-color="#13ce66"
            :active-value="1"
            :inactive-value="0"
          />
        </el-form-item>
        <el-form-item label="角色描述" label-width="150px" prop="description">
          <el-input v-model="addForm.description" />
        </el-form-item>
        <el-form-item label-width="150px">
          <el-button type="primary" @click="submitForm">确认修改</el-button>
          <el-button @click="close">取 消</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import { getRoleListRequest, addRoleRequest, deleteRoleRequest, updateRoleRequest } from '@/api/role'

export default {
  name: 'Role',
  data() {
    return {
      roleList: [],
      form: {
        page: 1,
        pagesize: 3
      },
      total: 0,
      showDialog: false,
      // 下面是新增的对象
      addForm: {
        name: '',
        description: '',
        state: 1
      },
      // 下面是编辑/修改的对象
      editForm: {
        name: '',
        description: '',
        state: 1
      },
      rules: {
        name: [
          { required: true, message: '请输入角色名称', trigger: 'blur' },
          { min: 2, max: 20, message: '角色名称位数在2-20位', trigger: 'blur' }
        ],
        description: [
          { required: true, message: '请输入描述', trigger: 'blur' },
          { min: 2, max: 20, message: '描述位数在2-20位', trigger: 'blur' }
        ]
      }
      // 表格有10行数据，不能只用一个变量来控制状态，一定需要10个变量
      // isEdit1: true,
      // isEdit2: true,
    }
  },
  // watch主要是用来监听某些数据的变化
  watch: {
    '$route': {
      handler(newVal) {
        console.log(11, newVal)
      },
      // 已进入组件，立即执行这个监听的回调函数
      immediate: true,
      // 深度监听，对象层级不管有多深，都能够监听
      deep: true
    }
  },
  // {a: {b: { c: { nane: 'zxxx'} } }}
  created() {
    this.getRoleList()
  },
  methods: {
    async getRoleList() {
      const res = await getRoleListRequest(this.form)
      this.roleList = res.data.rows
      this.total = res.data.total
      this.roleList.forEach(item => {
        // 给每一个对象添加一个isEdit属性，用来控制每一行是否是 编辑状态还是 展示数据状态
        // 一定要有一个思维， 数据驱动视图， 页面上的变化，最终都是由数据控制的，例如有10行数据有
        // 编辑和展示的 状态切换，那么就需要 有10个变量去控制驱动视图变化，页面通过v-if去判断
        // vue的数据要响应式的发生变化，在最开始的时候，数据只有绑定到 data上面，才会被vue的的底层方法
        // Object.defineproperty(obj, 'total', {get(){}, set(){}}) 递归进行 响应式数据get set的转换,劫持
        // 后面model发生了改变，会立即调用set函数，通知视图去更新。 view发生了变量，也会同步到model的改变
        // vue2 用 Object.defineproperty这个方法，有什么缺陷？
        // 对于对象， 无法检测属性的添加或移除
        // 对于数组，通过索引号修改数组，或者直接修改数组length长度，没有响应式，js数据更新了，但是页面不会更新
        // 对于数组，一共只有7个数组变异方法能够触发响应式？
        // 对于以上情况，vue给我们提供了一个方法  set--- 底层就会调用defineproperty，将我们的对象转换为get，set的形式

        // vue3 响应式原理 更改为了 new Proxy() 直接将整个对象，进行代码，在这个里面进行依赖的收集和更新
        // item.isEdit = false

        // Vue.set(xxxxx)  这句话是在 js文件里面
        this.$set(item, 'isEdit', false)
      })
    },
    test(a) {
      console.log(a)
    },
    handleCurrentChange(val) {
      this.form.page = val
      this.getRoleList()
    },
    close() {
      // 关闭弹窗，不要把下面代码写出去了，因为关闭弹窗除了关闭以外，还会做其他的事情
      this.showDialog = false
      // element-ui 提供的 原生的 重置的方法
      // 在我们当前项目里面直接找， 凡是有validate 的地方，就有重置的函数
      this.$refs.ruleForm.resetFields()
    },
    submitForm() {
      // 所有检验规则通过以后，在打印
      this.$refs.ruleForm.validate(async(valid) => {
        if (valid) {
          // 只要进入了这个if分支，表示页面所有校验通过
          // console.log(this.addForm)
          await addRoleRequest(this.addForm)
          // 添加成功以后，通过经验我们知道， 1. 关闭弹窗  2. 友好的提示  3.重新渲染（刷新页面）
          this.close()
          this.$message.success({ message: '新增成功' })
          // 添加成功以后，刷新页面之前，将页码值修改为1，让页面刷新的时候，回到第一页
          // 如果为了提升用户体验，可以立马看到最新我自己添加的数据，就要去到最后一页 （作业）
          this.form.page = 1
          this.getRoleList()
        }
      })
    },
    // 删除
    delRoleTmp(id) {
      this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        console.log(id)
        this.$message({
          type: 'success',
          message: '删除成功!'
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },
    // 第二种删除
    async confirm(id) {
      try {
        await deleteRoleRequest(id)
        // 下面代码是 删除成功才会执行
        this.$message({
          type: 'success',
          message: '删除成功'
        })
        // 当我们去删除 最后一页的时候，当最后一页 又只有一条数据的时候，就会有bug
        // 注意点： 当数组只有一个元素的时候，一定是最后一页，因为前面的页面，每页都有3条数据，都满了，才到下一个页面里面来的，
        if (this.roleList.length === 1) {
          // 只要有--的操作，一定会有负数请求
          // this.form.page = 1
          if (this.form.page > 1) {
            // this.form.page = this.form.page - 1
            // this.form.page -= 1
            // 下面代码的简写，是上面两种方式的 优化。就是自己减一再赋值给自己
            this.form.page--
          }
        }
        // 刷新页面
        this.getRoleList()
      } catch (err) {
        console.log('删除接口报错')
      }
    },
    // 编辑按钮的事件
    editRowTmp(row) {
      // 打开当前行之前，做一个排他思想，将其他的已经打开的关闭掉，保证同一个时间点只能编辑一行数据
      // 这个能否同时打开编辑多个，取决于公司的产品经理，通用的场景是只能打开编辑一行数据
      // eslint-disable-next-line no-return-assign
      this.roleList.forEach(item => item.isEdit = false)
      row.isEdit = true
      // 下面不能直接写等号
      // this.editForm = row
      // row就几个普通数据类型，只有一层数据的拷贝 可以用展开运算符，若果多层对象，就需要使用深拷贝
      this.editForm = { ...row }
      console.log(row)
    },
    async editSubmitTmp() {
      await updateRoleRequest(this.editForm)
      // 更新成功以后，1.给个提示 2. 刷新页面，回到首页 （凡是有分页的页面，都要记住当前在第几页）
      this.$message.success({ message: '更新成功' })
      this.form.page = 1 // 跳转回第一页，这个可以不加，也可以加，具体看产品需求
      this.getRoleList()
    }
  }
}
</script>

<style lang="scss" scoped>
.role-container {
  margin: 30px 50px;
  .rc-2 {
    margin: 20px 0;
  }
  .rc-3 {
    text-align: right;
  }
}
</style>
